#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
#include <math.h>
#include <vector> 
#include <cassert>
#include <fstream>
#include <iostream>


 
void write_mat(const char* fpath, std::vector<  float  > y) { 
  std::ofstream fout(fpath, std::ios::out | std::ios::binary);
  assert(fout);
  int len = y.size();
 
  fout.write( (char*)&len, sizeof(int));
  fout.write( (char*)&y[0], sizeof(float)*len);
  fout.close();
}


class myGL : public Fl_Gl_Window { 
  std::vector<float> v;
  int p;
  
  void draw() {
    printf("width: %d, height: %d\n", w(), h());
    if (!valid()) {
      valid(1);
      glMatrixMode (GL_PROJECTION);
      glLoadIdentity ();
      glOrtho (0, w(), h(), 0, 0, 1);
      glMatrixMode (GL_MODELVIEW);
      glDisable(GL_DEPTH_TEST);
    }
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    
    //white line across the center of the screen.
    glBegin(GL_LINE);
    glVertex2f(0, h()/2);
    glVertex2f(w(), h()/2);
    glEnd();

    glColor3f(1.0, .5, 1.0);
    glBegin(GL_LINE_STRIP);
    for ( unsigned i=0; i<v.size(); i++ ) {
      glVertex2f( ((float)i/(v.size()-1)) * w() , v[i]*h() );
    }
    glEnd();
  }
  
  int handle( int event ) {
    switch ( event ) {
    case FL_DRAG:
    case FL_PUSH:
      if( Fl::event_button() == 1 ) {
	printf("Left mouse button pressed.\n");
	printf("width: %d\n", w());
	
	// figure out relevant indexes
	float mouseX = (float) Fl::event_x();
	float idx =  mouseX / w() * v.size();
	float pdx =  (mouseX - 1) / w() * v.size();
	float ndx =  (mouseX + 1) / w() * v.size();
	printf("p: %f, i: %f, n: %f\n", pdx, idx, ndx);
	
	//don't try to index a point that doesn't exit
	if( floor(idx) < 0 || floor(idx) > v.size()+1 ) { return 1; }

	//assign this click to the proper point,
	//but normalize it so it makes sense when we resize
	int choose = (int)floor(idx);
	float val  = (float)Fl::event_y()/h();
	
	// confine the y-value to within the screen.
	if( val > 1.0 ) val = 1;
	if( val < 0.0 ) val = 0;

	// put the 'value' in the point we've selected.
	v[choose] = val;

	// don't 'skip' points when we're dragging
	if( p != -1 && abs(p-choose) > 1 ) {
	  int inc = (p<choose)?1:-1;
	  for( int iidx = inc;  p+iidx != choose; iidx+=inc ) {
	    v[p+iidx] = val;
	  }
	} 
	
	// now remember the current point as the last one we've updated.
	p = (int)floor(idx);
	redraw();
	return 1;
      case FL_RELEASE:
	// forget about having pressed a previous point if we release the mouse.
	p = -1;
      default:
	// letting the base class handle events I don't care
	// about, or don't dare mess with.
	return Fl_Gl_Window::handle(event);
      }
    }
  }

  void resize(int X,int Y,int W,int H) {
    Fl_Gl_Window::resize(X,Y,W,H);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    glViewport(0,0,W,H);
    glOrtho (0, W, H, 0, 0, 1);
    glMatrixMode (GL_MODELVIEW);
    glDisable(GL_DEPTH_TEST);
    printf("resizing!\n");
    redraw();
  }

public:
  myGL(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) {
    end();
    v.resize(500, (float)H/2);
  }
};



int main(void) {
  // this creates our window
  Fl_Window win(500, 500);
  myGL gWin(10, 10, win.w()-20, win.h()-20);
  //not sure how/why this works
  win.resizable(&gWin);
  //makes the window show up
  win.show();
  // This causes the fltk stuff to run until the window's closed
  return(Fl::run());
}
